package com.example.birdfriends.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.birdfriends.pojo.message.Message;
import com.example.birdfriends.pojo.user.User;
import com.example.birdfriends.service.MessageService;
import com.example.birdfriends.service.UserService;
import com.example.birdfriends.utils.encoder.EncoderServer;
import com.example.birdfriends.utils.message.MessageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ServerEndpoint(value = "/groupChat/{receiverId}/{userId}", encoders = EncoderServer.class)
public class WebSocketServerController {
    private static ApplicationContext applicationContext;
    private MessageUtil messageUtil;
    private MessageService messageService;
    private static ConcurrentHashMap<String, List<Session>> groupMemberInfoMap = new ConcurrentHashMap<>();
    private static ConcurrentHashMap<String, Set<Long>> onlineUserMap = new ConcurrentHashMap<>();

    public static void setApplicationContext(ApplicationContext applicationContext){
        WebSocketServerController.applicationContext = applicationContext;
    }


    private String roomNumber;
    // 收到消息调用方法
    @OnMessage
    public void onMessage(@PathParam("receiverId") Long receiverId, @PathParam("userId") Long userId, String message){
        String roomNumber;  // 获取这两个用户聊天的房间号
        if (groupMemberInfoMap.containsKey(userId+""+receiverId)){
            roomNumber = userId + "" + receiverId;
        }else {
            roomNumber = receiverId+""+ userId;
        }
        System.out.println("房间号："+roomNumber);
        messageUtil = applicationContext.getBean(MessageUtil.class);
        messageService = applicationContext.getBean(MessageService.class);

        List<Session> sessionList = groupMemberInfoMap.get(roomNumber);
//        System.out.println("会话个数:"+sessionList.size());
        Map<String, Object> oldMessageInfo = messageUtil.findFriendsAndMessage(userId, receiverId, "chat");
        if(message.contains("上线啦~")){
            // 上线获取聊天记录
            oldMessageInfo.replace("message", message);
            sessionList.forEach(item ->{
               try {
//                   System.out.println("session id："+item.getId());
                   item.getBasicRemote().sendObject(oldMessageInfo);
               }catch (Exception e) {
                   e.printStackTrace();
               }
            });
        } else if (message.contains("下线啦~")) {
            oldMessageInfo.replace("message", message);
            sessionList.forEach(item ->{
                try {
//                    System.out.println("session id："+item.getId());
                    item.getBasicRemote().sendObject(oldMessageInfo);
                }catch (Exception e) {
                    e.printStackTrace();
                }
            });
        } else {
            // 发送消息更新聊天记录
            Message messagePo = JSONObject.parseObject(message, Message.class);
            messagePo.setCreateAt(new Timestamp(System.currentTimeMillis()));
            messagePo.setIsRead(0);  // 0表示未读状态
            // 将消息数据项存入数据库
//            System.out.print("待发送的消息:");messagePo.print();
            int add = messageService.addMessage(messagePo);  // 添加多次
            boolean success = add > 0;
            sessionList.forEach(item -> {
               try{
                   if (success){
                       // 双方add之后的聊天记录
                       Map<String, Object> newMessages = messageUtil.findFriendsAndMessage(userId, receiverId, "chat");
                       item.getBasicRemote().sendObject(newMessages);
                   } else {
                       // 双方原本的聊天记录
                       item.getBasicRemote().sendObject(oldMessageInfo);
                   }
               }catch (Exception e){
                   e.printStackTrace();
               }
            });
        }
    }

    // 获取当前房间号是否存在
    private void setRoomNumber(Session session, Long userId, Long receiverId){
        String roomNumber;
        String roomNumber1 = userId+""+receiverId, roomNumber2 = receiverId+""+userId;  // 房间号
        Map<String, List<Object>> ans = new HashMap<>();
        if (!groupMemberInfoMap.containsKey(roomNumber1) && !groupMemberInfoMap.containsKey(roomNumber2)){
            // 不存在二者的对话房间号，创建一个房间
            List<Session> sessionList = groupMemberInfoMap.computeIfAbsent(roomNumber1, k->new ArrayList<>());
            sessionList.add(session);
            Set<Long> userIdList = onlineUserMap.computeIfAbsent(roomNumber1, k-> new HashSet<>());
            userIdList.add(userId);
//            roomNumber = roomNumber1;
        }else {
            // 存在任一房间号，之间获取该房间号的对话
            if (groupMemberInfoMap.containsKey(roomNumber1)){
                roomNumber = roomNumber1;
            } else{
                roomNumber = roomNumber2;
            }
            List<Session> sessionList = groupMemberInfoMap.get(roomNumber);
            Set<Long> userIdList = onlineUserMap.get(roomNumber);
            if (!userIdList.contains(userId)){
                sessionList.add(session);
                userIdList.add(userId);
            }else if (!userIdList.contains(receiverId)){
                sessionList.add(session);
                userIdList.add(userId);
            }
        }
    }

    @OnOpen
    public void onOpen(Session session, @PathParam("receiverId") Long receiverId, @PathParam("userId") Long userId){
        log.info("Connection connected");
        log.info("sid:{}, rid:{}", userId, receiverId);
        // 设置当前对话的房间号
        setRoomNumber(session, userId, receiverId);
        // 发送我的上线通知给好友
        System.out.println(userId+"上线了");
        sendInfo(userId, receiverId, "上线啦~");
    }

    private UserService userService;

    public void  sendInfo(Long receiverId, Long userId, String info){
        userService = applicationContext.getBean(UserService.class);
        // 发送上线通知
        User friend = userService.findUserByUid(receiverId);  // 好友
        System.out.println("send info");
        String text = friend.getNickname()+info;

        // 将信息封装成HashMap
        onMessage(receiverId, userId, text);
    }

    // 关闭连接调用的方法
    @OnClose
    public void onClose(Session session, @PathParam("receiverId") Long receiverId, @PathParam("userId") Long userId){
        String roomNumber;
        if (groupMemberInfoMap.containsKey(userId+""+receiverId)){
            roomNumber = userId + "" + receiverId;
        }else {
            roomNumber = receiverId+""+ userId;
        }
        log.info("close connection from "+userId+" to "+receiverId);

        System.out.println("close websocket connection");

        List<Session> sessionList = groupMemberInfoMap.get(roomNumber);
        sessionList.remove(session);
        Set<Long> onlineUserSet = onlineUserMap.get(roomNumber);
        onlineUserSet.remove(userId);
        updateReadState(userId, receiverId);
        sendInfo(receiverId, userId, "下线啦~");
    }

    private void updateReadState(Long userId, Long receiverId){
        messageService = applicationContext.getBean(MessageService.class);
        // 退出聊天页面，当前用户退出聊天室，退出的时候将当前用户之间的聊天记录都设为已读，之后新增的都是未读
        Timestamp curTime = new Timestamp(System.currentTimeMillis());  // 当前时间
        Message updateMessagePo = new Message();
        updateMessagePo.setIsRead(1);  // 1表示消息已读状态
        updateMessagePo.setSenderId(userId);
        updateMessagePo.setReceiverId(receiverId);
        updateMessagePo.setCreateAt(curTime);
        int updateNumber = messageService.updateMessageReadState(updateMessagePo);
        log.info("修改"+updateNumber+"条消息阅读状态");
    }

    @OnError
    public void onError(Throwable error){
        error.printStackTrace();
        log.info("Connection error");
    }
}
